package com.mark.web.data.service.impl;

import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mark.common.Constant;
import com.mark.common.ServerResponse;
import com.mark.common.utils.*;
import com.mark.web.data.mapper.OrderItemMapper;
import com.mark.web.data.mapper.OrderMapper;
import com.mark.web.data.mapper.PayInfoMapper;
import com.mark.web.data.enums.OrderStatusEnum;
import com.mark.common.enums.PropertiesEnum;
import com.mark.common.exception.Campuso2oException;
import com.mark.web.data.exception.PayException;
import com.mark.web.data.entity.po.Order;
import com.mark.web.data.entity.po.OrderItem;
import com.mark.web.data.entity.po.PayInfo;
import com.mark.web.data.service.IPayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * @Description: 支付宝支付的业务逻辑实现
 * @Author: Mark
 * @CreateDate: 2018/8/14.
 * @Version: 2.0
 * @Copyright : 豆浆油条个人非正式工作室
 */
@Slf4j
@Service("payServiceImpl")
public class PayServiceImpl  implements IPayService{
    private static AlipayTradeService tradeService;
    static {

        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");

        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
    }
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private PayInfoMapper payInfoMapper;


    @Override
    public ServerResponse pay(String orderNo, Integer currentUserId, String path) {
        File targetFile = null;
        try {
            Map<String, String> resultMap = Maps.newHashMap();
            String[] arrOrderNo = orderNo.split(",");

            StringBuilder payOrderNo = new StringBuilder();
            BigDecimal total = new BigDecimal(0.0);
            List<OrderItem> orderItemLists = Lists.newArrayList();
            for (int i = 0; i < arrOrderNo.length; i++) {
                String orders = arrOrderNo[i];
                Long orderValue = Long.parseLong(orders);
                //根据用户Id和订单号查找订单
                Order order = orderMapper.selectOrder(currentUserId, orderValue, null);
                if (order == null) {
                    return ServerResponse.createByErrorMessage("用户没有该订单！");
                }
                total = BigDecimalUtil.add(total.doubleValue(), order.getPayment().doubleValue());
                //根据用户ID和订单号到订单明细表中查找相关信息
                List<OrderItem> orderItemList = orderItemMapper.getOrderListByOrderAndUserId(orderValue, currentUserId);
                for (OrderItem orderItem : orderItemList) {
                    orderItemLists.add(orderItem);
                }
                if (i == 0) {
                    payOrderNo.append(orders);
                } else {
                    payOrderNo.append("_").append(orders);
                }
            }

            resultMap.put("orderNo", payOrderNo.toString());

            // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
            // 需保证商户系统端不能重复，建议通过数据库sequence生成，
            String outTradeNo = payOrderNo.toString();

            // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
            String subject = new StringBuilder().append("校园二手交易平台扫码支付，订单号：").append(outTradeNo).toString();

            // (必填) 订单总金额，单位为元，不能超过1亿元
            // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
            String totalAmount = total.toString();

            // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
            // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
            String undiscountableAmount = "0";

            // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
            // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
            String sellerId = "";

            // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
            String body = new StringBuilder().append("订单:").append(outTradeNo).append("购买商品").append(totalAmount).append("元").toString();

            // 商户操作员编号，添加此参数可以为商户操作员做销售统计
            String operatorId = "test_operator_id";

            // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
            String storeId = "test_store_id";

            // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
            ExtendParams extendParams = new ExtendParams();
            extendParams.setSysServiceProviderId("2088100200300400500");

            //支付超时，定义为120分钟
            String timeoutExpress = "120m";

            // 商品明细列表，需填写购买商品详细信息，
            // List<OrderItem> orderItemList = orderItemMapper.getOrderListByOrderAndUserId(orderNo,currentUserId);//根据用户ID和订单号到订单明细表中查找相关信息
            List<GoodsDetail> goodsDetailList = Lists.newArrayList();
            //遍历
            for (OrderItem orderItem : orderItemLists) {
                // 创建商品信息，参数含义分别为商品id（使用国标）、商品名称、商品价格（单位为分）、商品数量
                //构建GoodsDetail实例
                GoodsDetail goodsDetail = GoodsDetail.newInstance(
                        orderItem.getProductId().toString(),
                        orderItem.getProductName(),
                        BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(), new Double(100).doubleValue()).longValue(),
                        orderItem.getQuantity());
                //加到List中
                goodsDetailList.add(goodsDetail);
            }

            //创建扫码支付请求builder，设置请求参数
            AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                    .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                    .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                    .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
                    .setTimeoutExpress(timeoutExpress)
                    //支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
                    .setNotifyUrl(PropertiesUtil.getProperty(PropertiesEnum.ALIPAY_CALLBACK_URL.getPropertiesName()))
                    .setGoodsDetailList(goodsDetailList);
            //调用支付宝API大气预支付
            AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
            switch (result.getTradeStatus()) {
                case SUCCESS:
                    log.info("支付宝预下单成功");

                    AlipayTradePrecreateResponse response = result.getResponse();
                    dumpResponse(response);
                    File folder = null;
                    try {
                        //创建路径中的文件夹
                        folder = new File(path);
                    } catch (Exception e) {
                        log.error("在路径{}中创建文件夹失败！请检查文件夹是否可读", path);
                    }
                    if (folder!=null && !folder.exists()) {
                        folder.setWritable(true);
                        folder.mkdirs();
                    }
                    //需要修改为运行机器上的路径(注意这里的path后面要加上/)
                    //二维码的的本地相对路径
                    String qrPath = String.format(path + "/qr-%s.png", response.getOutTradeNo());
                    //文件名
                    String qrFileName = String.format("qr-%s.png", response.getOutTradeNo());
                    //在本地的upload文件夹上生成二维码图片
                    ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
                    targetFile = new File(path, qrFileName);
                    MultipartFile multipartFile = FileUtil.fileToMultipartFile(targetFile);
                    String qrUrl = OSSClientUtil.uploadImg2Oss(multipartFile, "qr", currentUserId);

                    log.info("保存二维码的本地地址：qrPath:" + qrPath);
                    log.info("访问二维码的OOS地址：qrUrl:" + qrUrl);

                    resultMap.put("qrUrl", qrUrl);
                    return ServerResponse.createBySuccess(resultMap);
                case FAILED:
                    log.error("支付宝预下单失败!!!");
                    return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");

                case UNKNOWN:
                    log.error("系统异常，预下单状态未知!!!");
                    return ServerResponse.createByErrorMessage("系统异常，预下单状态未知!!!");
                default:
                    log.error("不支持的交易状态，交易返回异常!!!");
                    return ServerResponse.createByErrorMessage("不支持的交易状态，交易返回异常!!!");
            }
        }catch (Exception e){
            throw new PayException("pay",e.getClass()+e.getMessage());
        }finally {
            if(targetFile != null){
                boolean delete = targetFile.delete();
                if(!delete){
                    log.warn("删除文件失败：");
                }
            }
        }
    }

    @Override
    @Transactional(value = "mySysDataSourceTransactionManager", rollbackFor = Campuso2oException.class)
    public ServerResponse aliCallback(Map<String, String> params){
        try {
            //商户订单号
            String orderNos = params.get("out_trade_no");
            String[] arrOrder = orderNos.split("_");

            //遍历更新订单信息
            for (String orderNoString : arrOrder) {
                Long orderNo = Long.parseLong(orderNoString);
                //支付宝交易号
                String tradeNo = params.get("trade_no");
                //交易状态
                String tradeStatus = params.get("trade_status");

                //1.查看订单是否存在
                Order order = orderMapper.selectByOrderNo(orderNo);
                if (order == null) {
                    return ServerResponse.createByErrorMessage("校园二手平台的订单,回调忽略");
                }

                //2.对订单的状态进行判断(状态是已经支付以上)
                if (order.getEnableStatus() >= OrderStatusEnum.PAID.getCode()) {
                    return ServerResponse.createBySuccess("支付宝重复调用");
                }

                //3.如果交易成功，更新订单状态
                if (Constant.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)) {
                    //付款时间
                    order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment")));
                    //设置状态为已付款
                    order.setEnableStatus(OrderStatusEnum.PAID.getCode());
                    orderMapper.updateByPrimaryKeySelective(order);
                }

                //4.订单信息支付保存到数据库
                PayInfo payInfo = new PayInfo();
                payInfo.setUserId(order.getUserId());
                payInfo.setOrderNo(order.getOrderNo());
                payInfo.setPayPlatform(Constant.PayPlatformEnum.ALIPAY.getCode());
                payInfo.setPlatformNumber(tradeNo);
                payInfo.setPlatformStatus(tradeStatus);
                int effectNum = payInfoMapper.insert(payInfo);
                if(effectNum != 1){
                    throw new Campuso2oException("保存订单的支付信息失败！");
                }
            }
            return ServerResponse.createBySuccess();
        }catch (Exception e){
            throw new Campuso2oException("支付回调更新订单相关信息",e);
        }
    }

    @Override
    public ServerResponse queryOrderPayStatus(Integer userId, String orderNo) {
        try{
            String[] arrOrderNo = orderNo.split(",");
            for(String orderString : arrOrderNo){
                Long orderValue = Long.parseLong(orderString);
                //先检查这个订单是否存在
                Order order = orderMapper.selectOrder(userId,orderValue,null);
                if(order == null){
                    return ServerResponse.createByErrorMessage("用户没有该订单");
                }
                //如果订单的状态大于等于已经付款（包括已经发货之类的） 就是返回true
                if(order.getEnableStatus() >= Constant.OrderStatusEnum.PAID.getCode()){
                    return ServerResponse.createBySuccess();
                }
                return ServerResponse.createByError();
            }
            return ServerResponse.createByError();
        }catch (Exception e){
            throw new PayException("queryOrderPayStatus",e.getClass()+e.getMessage());
        }
    }

    private void dumpResponse(AlipayTradePrecreateResponse response) {
        if (response != null) {
            log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            log.info("body:" + response.getBody());
        }
    }
}
